//SPDX-FileCopyrightText: Copyright 2022-2024 深圳市同心圆网络有限公司
//SPDX-License-Identifier: GPL-3.0-only

package admin_project_api_serv

import (
	"context"
	"time"

	"atomgit.com/openlinksaas/api-server/admin_api_serv/admin_common"
	"atomgit.com/openlinksaas/api-server/api_common"
	"atomgit.com/openlinksaas/api-server/config"
	"atomgit.com/openlinksaas/api-server/dao"
	"atomgit.com/openlinksaas/api-server/dao/project_dao"
	"atomgit.com/openlinksaas/api-server/dao/user_dao"
	"atomgit.com/openlinksaas/proto-gen-go.git/project_api"
	"atomgit.com/openlinksaas/proto-gen-go.git/user_api"
	"go.mongodb.org/mongo-driver/mongo"
)

type ProjectAdminApiImpl struct {
	project_api.UnimplementedProjectAdminApiServer
	adminCfg *config.AdminCfg
}

func NewProjectAdminApiImpl(adminCfg *config.AdminCfg) *ProjectAdminApiImpl {
	return &ProjectAdminApiImpl{adminCfg: adminCfg}
}

func (apiImpl *ProjectAdminApiImpl) List(ctx context.Context, req *project_api.AdminListRequest) (*project_api.AdminListResponse, error) {
	emptyList := []*project_api.ProjectInfo{}

	sess, ok := dao.CacheDao.GetAdminSession(ctx, req.AdminSessionId)
	if !ok {
		return &project_api.AdminListResponse{
			Code:            project_api.AdminListResponse_CODE_WRONG_SESSION,
			ErrMsg:          "会话不存在",
			ProjectInfoList: emptyList,
		}, nil
	}
	if !sess.AuthOk {
		return &project_api.AdminListResponse{
			Code:            project_api.AdminListResponse_CODE_NOT_AUTH,
			ErrMsg:          "未授权会话",
			ProjectInfoList: emptyList,
		}, nil
	}
	adminUserCfg, err := admin_common.GetAdminUserConfig(ctx, apiImpl.adminCfg, sess.UserName)
	if err != nil {
		return nil, err
	}
	if !adminUserCfg.PermInfo.ProjectPerm.Read {
		return &project_api.AdminListResponse{
			Code:            project_api.AdminListResponse_CODE_NO_PERMISSION,
			ErrMsg:          "没有权限",
			ProjectInfoList: emptyList,
		}, nil
	}

	projectIdList := []string{}
	if req.FilterByUserId {
		projectIdList, err = project_dao.MemberInfoDao.ListProjectByMember(ctx, req.UserId)
		if err != nil {
			return nil, err
		}
	}
	listParam := &project_dao.ListProjectByAdminApiParam{
		FilterClosed:      req.FilterClosed,
		Closed:            req.Closed,
		FilterByKeyword:   req.FilterByKeyword,
		Keyword:           req.Keyword,
		FilterByRemove:    req.FilterByRemove,
		Remove:            req.Remove,
		FilterByProjectId: req.FilterByUserId,
		ProjectIdList:     projectIdList,
	}
	count, err := project_dao.ProjectInfoDao.CountByAdminApi(ctx, listParam)
	if err != nil {
		return nil, err
	}
	projectItemList, err := project_dao.ProjectInfoDao.ListByAdminApi(ctx, listParam, int64(req.Offset), int64(req.Limit))
	if err != nil {
		return nil, err
	}
	//补充成员信息
	userIdList := []string{}
	for _, projectItem := range projectItemList {
		userIdList = append(userIdList, projectItem.OwnerUserId)
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, userIdList)
	if err != nil {
		return nil, err
	}
	userItemMap := map[string]*user_dao.UserInfoDbItem{}
	for _, userItem := range userItemList {
		userItemMap[userItem.UserId] = userItem
	}
	//生成结果
	infoList := []*project_api.ProjectInfo{}
	for _, projectItem := range projectItemList {
		info := projectItem.ToProjectInfo(&project_api.UserProjectPerm{
			CanUpdate: true,
		})
		userItem, ok := userItemMap[info.OwnerUserId]
		if ok {
			info.OwnerDisplayName = userItem.BasicInfo.DisplayName
			info.OwnerLogoUri = userItem.BasicInfo.LogoUri
		}
		infoList = append(infoList, info)
	}
	return &project_api.AdminListResponse{
		Code:            project_api.AdminListResponse_CODE_OK,
		TotalCount:      count,
		ProjectInfoList: infoList,
	}, nil
}

func (apiImpl *ProjectAdminApiImpl) Get(ctx context.Context, req *project_api.AdminGetRequest) (*project_api.AdminGetResponse, error) {
	emptyInfo := &project_api.ProjectInfo{
		BasicInfo:       &project_api.BasicProjectInfo{},
		UserProjectPerm: &project_api.UserProjectPerm{},
	}

	sess, ok := dao.CacheDao.GetAdminSession(ctx, req.AdminSessionId)
	if !ok {
		return &project_api.AdminGetResponse{
			Code:        project_api.AdminGetResponse_CODE_WRONG_SESSION,
			ErrMsg:      "会话不存在",
			ProjectInfo: emptyInfo,
		}, nil
	}
	if !sess.AuthOk {
		return &project_api.AdminGetResponse{
			Code:        project_api.AdminGetResponse_CODE_NOT_AUTH,
			ErrMsg:      "未授权会话",
			ProjectInfo: emptyInfo,
		}, nil
	}
	adminUserCfg, err := admin_common.GetAdminUserConfig(ctx, apiImpl.adminCfg, sess.UserName)
	if err != nil {
		return nil, err
	}
	if !adminUserCfg.PermInfo.ProjectPerm.Read {
		return &project_api.AdminGetResponse{
			Code:        project_api.AdminGetResponse_CODE_NO_PERMISSION,
			ErrMsg:      "没有权限",
			ProjectInfo: emptyInfo,
		}, nil
	}

	projectItem, err := project_dao.ProjectInfoDao.Get(ctx, req.ProjectId)
	if err != nil {
		return &project_api.AdminGetResponse{
			Code:        project_api.AdminGetResponse_CODE_NO_PROJECT,
			ErrMsg:      "项目不存在",
			ProjectInfo: emptyInfo,
		}, nil
	}
	userItemList, err := user_dao.UserInfoDao.ListById(ctx, []string{projectItem.OwnerUserId})
	if err != nil {
		return nil, err
	}
	info := projectItem.ToProjectInfo(&project_api.UserProjectPerm{
		CanUpdate: true,
	})
	if len(userItemList) > 0 {
		info.OwnerDisplayName = userItemList[0].BasicInfo.DisplayName
		info.OwnerLogoUri = userItemList[0].BasicInfo.LogoUri
	}
	return &project_api.AdminGetResponse{
		Code:        project_api.AdminGetResponse_CODE_OK,
		ProjectInfo: info,
	}, nil
}

func (apiImpl *ProjectAdminApiImpl) Update(ctx context.Context, req *project_api.AdminUpdateRequest) (*project_api.AdminUpdateResponse, error) {
	sess, ok := dao.CacheDao.GetAdminSession(ctx, req.AdminSessionId)
	if !ok {
		return &project_api.AdminUpdateResponse{
			Code:   project_api.AdminUpdateResponse_CODE_WRONG_SESSION,
			ErrMsg: "会话不存在",
		}, nil
	}
	if !sess.AuthOk {
		return &project_api.AdminUpdateResponse{
			Code:   project_api.AdminUpdateResponse_CODE_NOT_AUTH,
			ErrMsg: "未授权会话",
		}, nil
	}
	adminUserCfg, err := admin_common.GetAdminUserConfig(ctx, apiImpl.adminCfg, sess.UserName)
	if err != nil {
		return nil, err
	}
	if !adminUserCfg.PermInfo.ProjectPerm.Update {
		return &project_api.AdminUpdateResponse{
			Code:   project_api.AdminUpdateResponse_CODE_NO_PERMISSION,
			ErrMsg: "没有权限",
		}, nil
	}

	userItem, err := user_dao.UserInfoDao.Get(ctx, req.OwnerUserId)
	if err != nil {
		return &project_api.AdminUpdateResponse{
			Code:   project_api.AdminUpdateResponse_CODE_NO_OWNER_USER,
			ErrMsg: "对应用户不存在",
		}, nil
	}
	if userItem.UserState != uint32(user_api.USER_STATE_USER_STATE_NORMAL) {
		return &project_api.AdminUpdateResponse{
			Code:   project_api.AdminUpdateResponse_CODE_NO_OWNER_USER,
			ErrMsg: "对应用户不是可用状态",
		}, nil
	}

	projectItem, err := project_dao.ProjectInfoDao.Get(ctx, req.ProjectId)
	if err != nil {
		return &project_api.AdminUpdateResponse{
			Code:   project_api.AdminUpdateResponse_CODE_NO_PROJECT,
			ErrMsg: "项目不存在",
		}, nil
	}

	nowTime := time.Now().UnixNano() / 1e6

	dbSess, err := dao.StartSession()
	if err != nil {
		return nil, err
	}
	defer dao.EndSession(dbSess)

	ret, err := dbSess.WithTransaction(ctx, func(sessCtx mongo.SessionContext) (interface{}, error) {
		if projectItem.OwnerUserId != req.OwnerUserId {
			err = api_common.AddMember(sessCtx, nowTime, projectItem, req.OwnerUserId, "")
			if err != nil {
				return nil, err
			}
		}
		err = project_dao.ProjectInfoDao.UpdateBasicInfo(sessCtx, req.ProjectId, &project_dao.BasicProjectInfoDbItem{
			ProjectName: req.BasicInfo.ProjectName,
			ProjectDesc: req.BasicInfo.ProjectDesc,
		})
		if err != nil {
			return nil, err
		}
		if projectItem.OwnerUserId != req.OwnerUserId {
			err = project_dao.ProjectInfoDao.SetOwner(sessCtx, req.ProjectId, req.OwnerUserId, nowTime)
			if err != nil {
				return nil, err
			}
		}
		return &project_api.AdminUpdateResponse{
			Code: project_api.AdminUpdateResponse_CODE_OK,
		}, nil
	})
	if err != nil {
		return nil, err
	}
	return ret.(*project_api.AdminUpdateResponse), nil
}
